"""
价格梯度模块
获取期权价格梯度信息
"""
import time
from typing import Dict, List, Optional
from datetime import datetime, timedelta
from loguru import logger

try:
    import okx.PublicData as PublicData
except ImportError:
    logger.warning("okx SDK未安装，请运行: pip install okx")
    PublicData = None


class TickBandsManager:
    """价格梯度管理器"""
    
    # 限速配置：5次/2s
    RATE_LIMIT_REQUESTS = 5
    RATE_LIMIT_WINDOW = 2.0  # 秒
    
    def __init__(self, sandbox: bool = True):
        """
        初始化价格梯度管理器
        
        Args:
            sandbox: 是否使用模拟盘，True=模拟盘(1)，False=实盘(0)
        """
        if PublicData is None:
            raise ImportError("okx SDK未安装，请运行: pip install okx")
        
        self.sandbox = sandbox
        flag = "1" if sandbox else "0"
        
        # 初始化OKX公共数据API
        self.public_api = PublicData.PublicAPI(flag=flag)
        
        # 限速控制
        self.request_times: List[float] = []  # 请求时间戳列表
        
        # 数据缓存
        self.tick_bands_cache: Dict[str, List[Dict]] = {}  # inst_type -> tick_bands_data
        self.cache_expire_time: Dict[str, datetime] = {}  # inst_type -> expire_time
        self.cache_duration = timedelta(hours=24)  # 缓存24小时
        
        logger.info(f"价格梯度管理器已初始化 (模式: {'模拟盘' if sandbox else '实盘'})")
    
    def _check_rate_limit(self):
        """
        检查并执行限速
        限速规则：5次/2s (IP)
        """
        now = time.time()
        
        # 移除2秒前的请求记录
        self.request_times = [t for t in self.request_times 
                             if now - t < self.RATE_LIMIT_WINDOW]
        
        # 如果达到限速上限，等待
        if len(self.request_times) >= self.RATE_LIMIT_REQUESTS:
            oldest_request = self.request_times[0]
            wait_time = self.RATE_LIMIT_WINDOW - (now - oldest_request)
            
            if wait_time > 0:
                logger.debug(f"触发限速，等待 {wait_time:.2f} 秒")
                time.sleep(wait_time)
                # 重新计算
                now = time.time()
                self.request_times = [t for t in self.request_times 
                                     if now - t < self.RATE_LIMIT_WINDOW]
        
        # 记录本次请求
        self.request_times.append(now)
    
    def get_tick_bands(self, inst_type: str, use_cache: bool = True) -> List[Dict]:
        """
        获取价格梯度
        
        Args:
            inst_type: 产品类型，目前仅支持 OPTION（期权）
            use_cache: 是否使用缓存
            
        Returns:
            价格梯度信息列表，每个交易品种包含以下字段：
            - instType: 产品类型
            - instFamily: 交易品种
            - tickBand: 价格梯度列表
                - minPx: 最小价格
                - maxPx: 最大价格
                - tickSz: 价格精度
        """
        # 检查缓存
        if use_cache and inst_type in self.tick_bands_cache:
            expire_time = self.cache_expire_time.get(inst_type)
            if expire_time and datetime.now() < expire_time:
                logger.debug(f"从缓存获取价格梯度: {inst_type}")
                return self.tick_bands_cache[inst_type]
        
        # 执行限速检查
        self._check_rate_limit()
        
        try:
            logger.info(f"获取价格梯度: {inst_type}")
            result = self.public_api.get_instrument_tick_bands(instType=inst_type)
            
            # 检查响应
            if result.get("code") != "0":
                error_msg = result.get("msg", "未知错误")
                logger.error(f"获取价格梯度失败: {error_msg}")
                raise RuntimeError(f"API错误: {error_msg}")
            
            # 提取数据
            data_list = result.get("data", [])
            logger.info(f"获取价格梯度成功: {len(data_list)} 个交易品种")
            
            # 更新缓存
            if use_cache:
                self.tick_bands_cache[inst_type] = data_list
                self.cache_expire_time[inst_type] = datetime.now() + self.cache_duration
            
            return data_list
            
        except Exception as e:
            logger.error(f"获取价格梯度异常: {e}")
            raise
    
    def get_option_tick_bands(self, use_cache: bool = True) -> List[Dict]:
        """
        获取期权价格梯度
        
        Args:
            use_cache: 是否使用缓存
            
        Returns:
            期权价格梯度列表
        """
        return self.get_tick_bands("OPTION", use_cache)
    
    def get_tick_bands_by_family(self, inst_family: str) -> Optional[Dict]:
        """
        根据交易品种获取价格梯度
        
        Args:
            inst_family: 交易品种，如 BTC-USD
            
        Returns:
            价格梯度信息，如果不存在返回None
        """
        tick_bands_list = self.get_option_tick_bands()
        
        for item in tick_bands_list:
            if item.get("instFamily") == inst_family:
                return item
        
        logger.warning(f"未找到交易品种 {inst_family} 的价格梯度")
        return None
    
    def get_tick_size_for_price(self, inst_family: str, price: float) -> Optional[float]:
        """
        根据价格获取对应的价格精度
        
        Args:
            inst_family: 交易品种
            price: 价格
            
        Returns:
            价格精度，如果不存在返回None
        """
        tick_bands_data = self.get_tick_bands_by_family(inst_family)
        
        if not tick_bands_data:
            return None
        
        tick_band_list = tick_bands_data.get("tickBand", [])
        
        for band in tick_band_list:
            min_px = float(band.get("minPx", 0))
            max_px = float(band.get("maxPx", float('inf')))
            
            if min_px <= price < max_px:
                return float(band.get("tickSz", 0))
        
        # 如果价格超出所有范围，返回最后一个梯度的精度
        if tick_band_list:
            return float(tick_band_list[-1].get("tickSz", 0))
        
        return None
    
    def get_tick_bands_details(self, inst_family: str) -> Dict:
        """
        获取交易品种的价格梯度详细信息（包含格式化数据）
        
        Args:
            inst_family: 交易品种
            
        Returns:
            详细信息字典
        """
        tick_bands_data = self.get_tick_bands_by_family(inst_family)
        
        if not tick_bands_data:
            raise ValueError(f"无法获取交易品种 {inst_family} 的价格梯度")
        
        # 格式化价格梯度
        tick_band_list = tick_bands_data.get("tickBand", [])
        formatted_bands = []
        
        for band in tick_band_list:
            formatted_bands.append({
                "min_price": float(band.get("minPx", 0)),
                "max_price": float(band.get("maxPx", float('inf'))),
                "tick_size": float(band.get("tickSz", 0)),
                "price_range": f"[{band.get('minPx')}, {band.get('maxPx')})",
            })
        
        return {
            "inst_type": tick_bands_data.get("instType"),
            "inst_family": inst_family,
            "tick_bands": formatted_bands,
            "total_bands": len(formatted_bands),
        }
    
    def validate_price(self, inst_family: str, price: float) -> Dict:
        """
        验证价格是否符合精度要求
        
        Args:
            inst_family: 交易品种
            price: 价格
            
        Returns:
            验证结果字典
        """
        tick_size = self.get_tick_size_for_price(inst_family, price)
        
        if tick_size is None:
            return {
                "valid": False,
                "price": price,
                "error": "无法获取价格精度"
            }
        
        # 检查价格是否符合精度
        remainder = price % tick_size
        is_valid = abs(remainder) < 1e-10 or abs(remainder - tick_size) < 1e-10
        
        # 计算最接近的有效价格
        if not is_valid:
            adjusted_price = round(price / tick_size) * tick_size
        else:
            adjusted_price = price
        
        return {
            "valid": is_valid,
            "price": price,
            "tick_size": tick_size,
            "adjusted_price": adjusted_price,
            "adjustment": adjusted_price - price,
        }
    
    def get_all_families(self) -> List[str]:
        """
        获取所有交易品种列表
        
        Returns:
            交易品种列表
        """
        tick_bands_list = self.get_option_tick_bands()
        
        families = [item.get("instFamily") for item in tick_bands_list]
        
        return families
    
    def compare_tick_bands(self, families: List[str]) -> List[Dict]:
        """
        比较多个交易品种的价格梯度
        
        Args:
            families: 交易品种列表
            
        Returns:
            比较结果列表
        """
        results = []
        
        for family in families:
            try:
                details = self.get_tick_bands_details(family)
                results.append({
                    "inst_family": family,
                    "total_bands": details["total_bands"],
                    "min_tick_size": min(band["tick_size"] for band in details["tick_bands"]),
                    "max_tick_size": max(band["tick_size"] for band in details["tick_bands"]),
                })
            except Exception as e:
                logger.error(f"获取 {family} 价格梯度失败: {e}")
        
        return results
    
    def clear_cache(self, inst_type: Optional[str] = None):
        """
        清除缓存
        
        Args:
            inst_type: 产品类型，如果为None则清除所有缓存
        """
        if inst_type:
            if inst_type in self.tick_bands_cache:
                del self.tick_bands_cache[inst_type]
            if inst_type in self.cache_expire_time:
                del self.cache_expire_time[inst_type]
            logger.info(f"已清除 {inst_type} 的缓存")
        else:
            self.tick_bands_cache.clear()
            self.cache_expire_time.clear()
            logger.info("已清除所有价格梯度缓存")
    
    def get_cache_stats(self) -> Dict:
        """
        获取缓存统计信息
        
        Returns:
            缓存统计字典
        """
        total_cached = len(self.tick_bands_cache)
        valid_cached = sum(1 for inst_type in self.tick_bands_cache.keys()
                          if inst_type in self.cache_expire_time and
                          datetime.now() < self.cache_expire_time[inst_type])
        
        return {
            "total_cached": total_cached,
            "valid_cached": valid_cached,
            "expired_cached": total_cached - valid_cached,
            "cache_duration_hours": self.cache_duration.total_seconds() / 3600,
        }


# 便捷函数
def get_option_tick_bands(sandbox: bool = True) -> List[Dict]:
    """
    便捷函数：获取期权价格梯度
    
    Args:
        sandbox: 是否使用模拟盘
        
    Returns:
        期权价格梯度列表
    """
    manager = TickBandsManager(sandbox=sandbox)
    return manager.get_option_tick_bands()


def get_tick_size_for_price(inst_family: str, price: float, sandbox: bool = True) -> Optional[float]:
    """
    便捷函数：根据价格获取对应的价格精度
    
    Args:
        inst_family: 交易品种
        price: 价格
        sandbox: 是否使用模拟盘
        
    Returns:
        价格精度
    """
    manager = TickBandsManager(sandbox=sandbox)
    return manager.get_tick_size_for_price(inst_family, price)


def validate_price(inst_family: str, price: float, sandbox: bool = True) -> Dict:
    """
    便捷函数：验证价格是否符合精度要求
    
    Args:
        inst_family: 交易品种
        price: 价格
        sandbox: 是否使用模拟盘
        
    Returns:
        验证结果字典
    """
    manager = TickBandsManager(sandbox=sandbox)
    return manager.validate_price(inst_family, price)
